﻿using OpenTK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LDLib
{
    /// <summary>
    ///  A collection of mesh generation tools
    /// </summary>
    public static class MeshTools
    {
        /// <summary>
        /// Creates an XY plane
        /// </summary>
        /// <param name="size">Size of the plane</param>
        /// <returns>A plane mesh</returns>
        public static Mesh CreatePlaneXY(Vector2 size)
        {
            size = new Vector2(size.X + float.Epsilon, size.Y + float.Epsilon);

            Mesh mesh = new Mesh();

            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, 0f), Vector3.UnitZ, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, 0f), Vector3.UnitZ, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, 0f), Vector3.UnitZ, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, 0f), Vector3.UnitZ, new Vector2(1f, 1f)));

            mesh.Indices.Add(0);
            mesh.Indices.Add(1);
            mesh.Indices.Add(2);
            mesh.Indices.Add(2);
            mesh.Indices.Add(1);
            mesh.Indices.Add(3);

            mesh.SetupMesh();

            return mesh;
        }

        /// <summary>
        /// Constructs an XZ plane
        /// </summary>
        /// <param name="size">Size of the plane</param>
        /// <returns>A plane mesh</returns>
        public static Mesh CreatePlaneXZ(Vector2 size)
        {
            size = new Vector2(size.X + float.Epsilon, size.Y + float.Epsilon);

            Mesh mesh = new Mesh();

            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, 0f, size.Y / 2f), Vector3.UnitY, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, 0f, size.Y / 2f), Vector3.UnitY, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, 0f, -size.Y / 2f), Vector3.UnitY, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, 0f, -size.Y / 2f), Vector3.UnitY, new Vector2(1f, 1f)));

            mesh.Indices.Add(0);
            mesh.Indices.Add(1);
            mesh.Indices.Add(2);
            mesh.Indices.Add(2);
            mesh.Indices.Add(1);
            mesh.Indices.Add(3);

            mesh.SetupMesh();

            return mesh;
        }

        public static Mesh CreateBox(Vector3 size)
        {
            Mesh mesh = new Mesh();

            // Front
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, size.Z / 2f), Vector3.UnitZ, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, size.Z / 2f), Vector3.UnitZ, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, size.Z / 2f), Vector3.UnitZ, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, size.Z / 2f), Vector3.UnitZ, new Vector2(1f, 1f)));
            mesh.Indices.Add(0);
            mesh.Indices.Add(1);
            mesh.Indices.Add(2);
            mesh.Indices.Add(2);
            mesh.Indices.Add(1);
            mesh.Indices.Add(3);

            // Back
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, -size.Z / 2f), -Vector3.UnitZ, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, -size.Z / 2f), -Vector3.UnitZ, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, -size.Z / 2f), -Vector3.UnitZ, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, -size.Z / 2f), -Vector3.UnitZ, new Vector2(1f, 1f)));
            mesh.Indices.Add(4);
            mesh.Indices.Add(5);
            mesh.Indices.Add(6);
            mesh.Indices.Add(6);
            mesh.Indices.Add(5);
            mesh.Indices.Add(7);

            // Top
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, size.Z / 2f), Vector3.UnitY, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, size.Z / 2f), Vector3.UnitY, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, -size.Z / 2f), Vector3.UnitY, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, -size.Z / 2f), Vector3.UnitY, new Vector2(1f, 1f)));
            mesh.Indices.Add(8);
            mesh.Indices.Add(9);
            mesh.Indices.Add(10);
            mesh.Indices.Add(10);
            mesh.Indices.Add(9);
            mesh.Indices.Add(11);

            // Bottom
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, -size.Z / 2f), -Vector3.UnitY, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, -size.Z / 2f), -Vector3.UnitY, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, size.Z / 2f), -Vector3.UnitY, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, size.Z / 2f), -Vector3.UnitY, new Vector2(1f, 1f)));
            mesh.Indices.Add(12);
            mesh.Indices.Add(13);
            mesh.Indices.Add(14);
            mesh.Indices.Add(14);
            mesh.Indices.Add(13);
            mesh.Indices.Add(15);

            // Left
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, -size.Z / 2f), -Vector3.UnitX, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, -size.Y / 2f, size.Z / 2f), -Vector3.UnitX, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, -size.Z / 2f), -Vector3.UnitX, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(-size.X / 2f, size.Y / 2f, size.Z / 2f), -Vector3.UnitX, new Vector2(1f, 1f)));
            mesh.Indices.Add(16);
            mesh.Indices.Add(17);
            mesh.Indices.Add(18);
            mesh.Indices.Add(18);
            mesh.Indices.Add(17);
            mesh.Indices.Add(19);

            // Right
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, size.Z / 2f), Vector3.UnitX, new Vector2(0f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, -size.Y / 2f, -size.Z / 2f), Vector3.UnitX, new Vector2(1f, 0f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, size.Z / 2f), Vector3.UnitX, new Vector2(0f, 1f)));
            mesh.Vertices.Add(new Vertex(new Vector3(size.X / 2f, size.Y / 2f, -size.Z / 2f), Vector3.UnitX, new Vector2(1f, 1f)));
            mesh.Indices.Add(20);
            mesh.Indices.Add(21);
            mesh.Indices.Add(22);
            mesh.Indices.Add(22);
            mesh.Indices.Add(21);
            mesh.Indices.Add(23);

            mesh.SetupMesh();

            return mesh;
        }
    }
}
